package it.uniroma3.dia.ia.textcategorization.benchmark;

import java.util.HashMap;
import java.util.Map;
import it.uniroma3.dia.ia.textcategorization.categorizer.Categorizer;
import it.uniroma3.dia.ia.textcategorization.model.Category;
import it.uniroma3.dia.ia.textcategorization.model.Text;

/**
 * 
 * This class allows to benchmark a Categorizer.
 * 
 * @author Marco Liceti.
 *
 */
public final class Benchmark {
	
	/**
	 * 
	 * Executes a benchmark.
	 * 
	 * @param categorizer The Categorizer to benchmark.
	 * @param testSet The test set.
	 * @return a Report instance with statistics about the benchmark.
	 * 
	 */
	public static Report getReport(Categorizer categorizer, Map<Text, Category> testSet) {
		// For each category, let's count
		// the number of texts assigned to
		Map<Category, Integer> counter_a = new HashMap<Category, Integer>();
		// the number of texts belonging to
		Map<Category, Integer> counter_b = new HashMap<Category, Integer>();
		// the number of texts correctly assigned
		Map<Category, Integer> counter_c = new HashMap<Category, Integer>();
		for (Category category : categorizer.getCategories()) {
			counter_a.put(category, new Integer(0));
			counter_b.put(category, new Integer(0));
			counter_c.put(category, new Integer(0));
		}
		for (Text text : testSet.keySet()) {
			Category predicted = categorizer.categorize(text);
			int a = counter_a.get(predicted);
			a++;
			counter_a.put(predicted, a);
			Category actual = testSet.get(text);
			int b = counter_b.get(actual);
			b++;
			counter_b.put(actual, b);
			if (predicted.equals(actual)) {
				int c = counter_c.get(actual);
				c++;
				counter_c.put(actual, c);
			}
		}
		
		// Precision and recall calculation
		Map<Category, Double> precision_map = new HashMap<Category, Double>();
		Map<Category, Double> recall_map = new HashMap<Category, Double>();
		for (Category category : categorizer.getCategories()) {
			Integer a = counter_a.get(category);
			Integer b = counter_b.get(category);
			Integer c = counter_c.get(category);
			
			Double precision = null;
			if (a != 0) precision = ((double) c) / a;
			precision_map.put(category, precision);
			
			Double recall = null;
			if (b != 0) recall = ((double) c) / b;
			recall_map.put(category, recall);
		}
		
		return new Report(precision_map, recall_map);
	}

}
